-- ======================================================================
-- Hell Lua Bus
-- 
-- Copyright 2012-2013Hell-Prototypes
--
-- http://www.hellprototypes.com/
--
-- This is free software, licensed under the terms of the GNU General
-- Public License as published by the Free Software Foundation.
-- ======================================================================

usb =require('libhlb')

module(..., package.seeall);

port_mask = {[0]=0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000}

-- HVPP pin index define -------------------------------------------------------
HVPP_OE_PIN			= 9
HVPP_XTAL1_PIN		= 8
HVPP_XA1_PIN		= 11
HVPP_BS2_PIN		= 11
HVPP_BS1_PIN		= 12
HVPP_WR_PIN			= 10

-- -----------------------------------------------------------------------------
function io_init()
	local ret
	local init_io_data = port_mask[HVPP_OE_PIN]
	local init_oe_data = port_mask[HVPP_OE_PIN] + port_mask[HVPP_XTAL1_PIN] + port_mask[HVPP_BS2_PIN] + port_mask[HVPP_BS1_PIN] + port_mask[HVPP_WR_PIN]

	ret = hlb.port_write(init_io_data)
	if ret < 0 then
		print("io_init : hlb_port_write ret = ", ret)
		return false
	end
	
	ret = hlb.port_oe(init_oe_data)
	if ret < 0 then
		print("io_init : hlb_port_oe ret = ", ret)
		return false
	end
	hlb.msdelay(100)
	
	return true
end

function data_bus_output()
	ret = hlb.byte_oe(0xff)
	if ret < 0 then
		print("data_bus_output : fail ret = ", ret)
		return false
	end
	return true
end

function data_bus_input()
	ret = hlb.byte_oe(0x00)
	if ret < 0 then
		print("data_bus_input : fail ret = ", ret)
		return false
	end
	local ret = hlb.byte_write(0x00)
	if ret < 0 then
		print("load_command: byte write fail")
		return false
	end

	return true
end

function pin_set(pin)
	local ret = hlb.set_bit( pin )
	if ret < 0 then
		print("Pin" .. pin .." : hlb_set_bit ret = ", ret)
		return false
	end
	return true
end

function pin_reset( pin )
	local ret = hlb.clr_bit( pin )
	if ret < 0 then
		print("Pin" .. pin .." : hlb_clr_bit ret = ", ret)
		return false
	end
	return true
end
-- -----------------------------------------------------------------------------
function pwr_on_12v()
	return hlb.ctrl_12V(1)
end
function pwr_off_12v()
	return hlb.ctrl_12V(0)
end
function pwr_on_5v()
	
end
function pwr_off_5v()
	
end
-- -----------------------------------------------------------------------------
function enter_HVPP_mode()

	--1. Set Prog_enable pins listed in  Table 72 on page 162 to “0000”, RESET pin and VCC to 0V.
	local succ = io_init()
	if not succ then
		print("io init fail")
		return false
	end
	--2. Apply 4.5 - 5.5V between VCC and GND.
	-- We Supply VCC = 5V all the time
	print("Ready to work:")
	io.write("\r\n1: Press the key on board to pull down XA0, Then Press Enter key to continue ...")
	io.read()
	print("")
	--3. Ensure that VCC reaches at least 1.8V within the next 20 µs.
	hlb.usdelay(20)
	--4. Wait 20 - 60 µs, and apply 11.5 - 12.5V to RESET.
	pwr_on_12v()
	--5. Keep the Prog_enable pins unchanged for at least 10µs after the High-voltage has been
	--   applied to ensure the Prog_enable Signature has been latched. 
	hlb.msdelay(500)
	--6. Wait at least 300 µs before giving any parallel programming commands. 
--	io.write("\r\nRelease the pressed key and Press Enter key to continue ...")
--	io.read()
	print("")
	pin_set(HVPP_WR_PIN)
	hlb.msdelay(50)
	return true
end

function exit_HVPP_mode()
--7. Exit Programming mode by power the device down or by bringing RESET pin to 0V.
	pwr_off_12v()
	pwr_off_5v()
end
-- -----------------------------------------------------------------------------

function load_command(cmd)
	hlb.msdelay(5)
	local ret = hlb.byte_write(cmd)
	if ret < 0 then
		print("load_command: byte write fail")
		return false
	end

	hlb.msdelay(5)
	if not pin_set(HVPP_XA1_PIN) then
		return false
	end

	hlb.msdelay(5)
	if not pin_set(HVPP_XTAL1_PIN) then
		return false
	end
	hlb.msdelay(10)
	if not pin_reset(HVPP_XTAL1_PIN) then
		return false
	end
	hlb.msdelay(5)
	if not pin_reset(HVPP_XA1_PIN) then
		return false
	end
	
	return true
end

function load_data(data)
	hlb.msdelay(5)
	local ret = hlb.byte_write(data)
	if ret < 0 then
		print("load_command: byte write fail")
		return false
	end
	hlb.msdelay(5)
	if not pin_set(HVPP_XTAL1_PIN) then
		return false
	end
	hlb.msdelay(10)
	if not pin_reset(HVPP_XTAL1_PIN) then
		return false
	end
	
	return true
end

function read_one_byte_signature(index)
	if index < 0 then
		return -1
	end
	if index > 2 then
		return -2
	end
	
	if not data_bus_output() then
		return -3
	end
	
	if not load_command(0x08) then
		print("read_one_signature_byte: load_command fail")
		return -4
	end
	
	hlb.msdelay(5)
	
	if not load_data(index) then
		print("read_one_signature_byte: load_command fail")
		return -5
	end
	
	hlb.msdelay(5)
	if not data_bus_input() then
		return -9
	end

	hlb.msdelay(5)
	if not pin_reset(HVPP_OE_PIN) then
		return -6
	end
	hlb.msdelay(5)
	local ret = hlb.byte_read()
	if ret < 0 then
		print("read_one_signature_byte: hlb_byte_read fail")
		return -7
	end
	
	if not pin_set(HVPP_OE_PIN) then
		return -8
	end
	
	return ret
end

function read_signature()
	local sig = {}
	for i=0, 2 do
		local ret = read_one_byte_signature(i)
		if ret < 0 then
			print("read_one_signature_byte: hlb_byte_read fail")
			sig = {}
			return sig;
		end
		sig[i+1] = ret
	end
	
	return sig;
end

function read_one_fuse_and_lock_byte(index)
	local ret

	if not pin_reset(HVPP_BS2_PIN) then
		return -10
	end
	if not pin_reset(HVPP_BS1_PIN) then
		return -12
	end
	if not data_bus_output() then
		return -1
	end
	
	if not load_command(0x04) then
		print("read_one_signature_byte: load_command fail")
		return -2
	end
	
	if not data_bus_input() then
		return -3
	end

	if index == 0 then

	end
	if index == 1 then
		if not pin_set(HVPP_BS1_PIN) then
			return -10
		end
		if not pin_set(HVPP_BS2_PIN) then
			return -10
		end
	end
	if index == 2 then
		if not pin_set(HVPP_BS2_PIN) then
			return -10
		end
	end
	if index == 3 then
		if not pin_set(HVPP_BS1_PIN) then
			return -10
		end
	end

	if not pin_reset(HVPP_OE_PIN) then
		return -4
	end

	hlb.msdelay(2)
	ret = hlb.byte_read() -- read fuse low bits
	if ret  < 0 then
		print("read_one_signature_byte: hlb_byte_read fail")
		return -5
	end
	
	if not pin_set(HVPP_OE_PIN) then
		return -4
	end

	if not pin_reset(HVPP_BS2_PIN) then
		return -10
	end
	if not pin_reset(HVPP_BS1_PIN) then
		return -12
	end
	
	return ret
end

function read_fuse()
	local fuse = {}
	
	fuse[1] = read_one_fuse_and_lock_byte(0)
	fuse[2] = read_one_fuse_and_lock_byte(1)
	fuse[3] = read_one_fuse_and_lock_byte(2)
	fuse[4] = read_one_fuse_and_lock_byte(3)
	return fuse
end

function wrkit()
	
	if not pin_reset(HVPP_WR_PIN) then
		return false
	end
	hlb.msdelay(2)
	if not pin_set(HVPP_WR_PIN) then
		return false
	end
	
	return true
end

function write_fuses(fuses)
	if #fuses ~= 3 then
		return false
	end

	if not data_bus_output() then
		return false
	end
	
	-- low fuse byte
	if not load_command(0x40) then
		print("read_one_signature_byte: load_command fail")
		return false
	end
	
	hlb.msdelay(2)
	
	if not load_data(fuses[1]) then
		print("read_one_signature_byte: load_command fail")
		return false
	end

	hlb.msdelay(2)
	
	if not wrkit() then
		return false
	end
	
	hlb.msdelay(100)
	
	-- high fuse byte
	if not load_command(0x40) then
		print("read_one_signature_byte: load_command fail")
		return false
	end
	
	hlb.msdelay(2)
	
	if not load_data(fuses[2]) then
		print("read_one_signature_byte: load_command fail")
		return false
	end
	
	hlb.msdelay(2)
	if not pin_set(HVPP_BS1_PIN) then
		return false
	end
	if not wrkit() then
		return false
	end
	
	hlb.msdelay(100)
	if not pin_reset(HVPP_BS1_PIN) then
		return false
	end
	hlb.msdelay(10)

	-- extended fuse byte
	if not load_command(0x40) then
		print("read_one_signature_byte: load_command fail")
		return false
	end
	
	hlb.msdelay(2)
	
	if not load_data(fuses[3]) then
		print("read_one_signature_byte: load_command fail")
		return false
	end
	
	hlb.msdelay(2)
	if not pin_set(HVPP_BS2_PIN) then
		return false
	end
	hlb.msdelay(2)
	if not wrkit() then
		return false
	end
	
	hlb.msdelay(100)
	if not pin_reset(HVPP_BS2_PIN) then
		return false
	end
	
	if not data_bus_input() then
		return false
	end
	return ret
end

-- -----------------------------------------------------------------------------
function device_open()
	local ret = hlb.usb_open()
	if ret < 0 then
		return false
	end
	
	return true
end

function device_close()
	local ret = hlb.usb_close()
	if ret < 0 then
		return false
	end
	
	return true
end